import javax.swing.*;
import javax.swing.border.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.Timer;	//@PEDRO

import java.awt.*;
import java.awt.event.*;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ChatUI {
	public enum State  //@PEDRO
	{
	    OPEN, CONNECTED, ON_ERROR
	}

	private ChatClient client;
	private ChatServerInt server;
	SimpleAttributeSet colors = new SimpleAttributeSet();
	LinkedHashSet<String> names = new LinkedHashSet<String>();
	private int keepalive=0;				//@PEDRO
	private State state = State.OPEN;			//@PEDRO


	Timer timer = new Timer( 500, new ActionListener(){  	//@PEDRO
	  @Override
	  public void actionPerformed( ActionEvent e ){
		switch(state)
		{
			// cliente abierto pero sin session
			case OPEN:
			{
				if (connect.getText().equals("Desconectarse")) 
					state = State.CONNECTED;
			}
			break;
			// Cliente con session a servidor
			case CONNECTED:
			{
				keepalive++;
				if(keepalive >= 6)
				{
					keepalive=0;
					try {
						server.AreYouAlive(client);
					} catch (Exception ex) {
						state = State.ON_ERROR;
					}
				}	 
			}
			break;
			// Chat open but not session to server
			case ON_ERROR:
			{
				doConnect();
				state = State.CONNECTED;
			}
			break;
		}
	  }
	} );
	public void doConnect() {
		if (connect.getText().equals("Conectarse")) {
			if (name.getText().length() < 2) {
				JOptionPane.showMessageDialog(frame, "Necesita utilizar un nombre de usuario.");
				return;
			}
			try {
				client = new ChatClient(name.getText());
				client.setGUI(this);
				server = (ChatServerInt) Naming.lookup("rmi://localhost/server");
//				server = (ChatServerInt) Naming.lookup("rmi://127.0.0.1/server");
				server.login(client);
				updateUsers(server.getConnected());
				connect.setText("Desconectarse");
				name.setEditable(false);
			} catch (Exception e) {
				e.printStackTrace();
				JOptionPane.showMessageDialog(frame, "ERROR, no se pudo conectar al servidor...");
			}
		} else {
			try {
				server.logout(client);
			} catch (RemoteException e) {
				e.printStackTrace();
			}
			updateUsers(null);
			connect.setText("Conectarse");
			name.setEditable(true);
		}
	}

	public void sendText() {
		if (connect.getText().equals("Conectarse")) {
			JOptionPane.showMessageDialog(frame, "Necesita conectarse primero.");
			return;
		}
		String st = tf.getText();
		st = "[" + name.getText() + "] " + st;
		tf.setText("");
		try {
			server.sendToAll(st);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void writeMsg(Message msg) { //alvaro
		String st = msg.text + "\n";
		Pattern p = Pattern.compile("\\[.*]");
		Matcher m = p.matcher(st);
		if (m.find())
		{
			try {
				String nameTemp = st.substring(m.start(0)+1,m.end(0)-1);
				ArrayList<String> nameList = new ArrayList<String>(names);
				switch (nameList.indexOf(nameTemp)%8) {
				case 0:
					StyleConstants.setForeground(colors, Color.ORANGE);
					break;
				case 1:
					StyleConstants.setForeground(colors, Color.BLUE);
					break;
				case 2:
					StyleConstants.setForeground(colors, Color.CYAN);
					break;
				case 3:
					StyleConstants.setForeground(colors, Color.GREEN);
					break;
				case 4:
					StyleConstants.setForeground(colors, Color.MAGENTA);
					break;
				case 5:
					StyleConstants.setForeground(colors, Color.PINK);
					break;
				case 6:
					StyleConstants.setForeground(colors, Color.RED);
					break;
				case 7:
					StyleConstants.setForeground(colors, Color.YELLOW);
					break;
					

				default:
					StyleConstants.setForeground(colors, Color.DARK_GRAY);
					break;
				}
				tx.getDocument().insertString(tx.getStyledDocument().getLength(),msg.num+" "+nameTemp + ": ", colors);
				StyleConstants.setForeground(colors, Color.BLACK);
				tx.getDocument().insertString(tx.getStyledDocument().getLength(),st.substring(m.end(0)), colors);
			} catch (BadLocationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public void deleteName(String sname){
		names.remove(sname);
		DefaultListModel<String> model = (DefaultListModel<String>) lst.getModel();
		model.removeElement(sname);
		lst.setModel(model);
	}
	
	public void updateUsers(Vector v) {
		DefaultListModel<String> listModel = new DefaultListModel<String>();
		if (v != null)
		{
			for (int i = 0; i < v.size(); i++) {
				try {
					String tmp = ((ChatClientInt) v.get(i)).getName();
					names.add(tmp);
					listModel.addElement(tmp);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}else{
			names.clear();
		}
		lst.setModel(listModel);
	}

	public static void main(String[] args) {
		System.out.println("Cliente del chat");
		ChatUI c = new ChatUI();
	}

	// User Interface code.
	public ChatUI() {
		frame = new JFrame("Chat distribuido");
		JPanel main = new JPanel();
		JPanel top = new JPanel();
		JPanel cn = new JPanel();
		JPanel bottom = new JPanel();
		tf = new JTextField();
		name = new JTextField();
		tx = new JTextPane();
		connect = new JButton("Conectarse");
		JButton bt = new JButton("Enviar");
		lst = new JList<String>();
		main.setLayout(new BorderLayout(5, 5));
		top.setLayout(new GridLayout(1, 0, 5, 5));
		cn.setLayout(new BorderLayout(5, 5));
		bottom.setLayout(new BorderLayout(5, 5));
		top.add(new JLabel("Nombre: "));
		top.add(name);
		top.add(connect);
		cn.add(new JScrollPane(tx), BorderLayout.CENTER);
		cn.add(lst, BorderLayout.EAST);
		bottom.add(tf, BorderLayout.CENTER);
		bottom.add(bt, BorderLayout.EAST);
		main.add(top, BorderLayout.NORTH);
		main.add(cn, BorderLayout.CENTER);
		main.add(bottom, BorderLayout.SOUTH);
		main.setBorder(new EmptyBorder(10, 10, 10, 10));
		// Events
		connect.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				doConnect();
			}
		});
		bt.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				sendText();
			}
		});
		tf.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				sendText();
			}
		});

		timer.setRepeats( true );	//@PEDRO
		timer.start();			//@PEDRO

		frame.setContentPane(main);
		frame.setSize(600, 600);
		frame.setVisible(true);
		StyleConstants.setFontFamily(colors, "Arial");
	}

	JTextPane tx;
	JTextField tf, name;
	JButton connect;
	JList<String> lst;
	JFrame frame;
}